\chapter{Implementatie prototype}
\label{ImplementatiePrototype}

Dit hoofdstuk beschrijft hoe men policies kan afdwingen op een stuk code gebruikmakend van de prototype. 
Verder zullen we de nodige aanpassingen uitleggen, die in Narcissus moesten gemaakt worden om dit mogelijk te maken. 
Voor het prototype zal er enkel een subset van alle gevoelige JavaScript operaties afgeschermd worden aangezien het nog om een proof-of-concept gaat. 
We hebben de operaties die we wel zullen afschermen zo gekozen dat er van elke soort operaties (property, function, Object, etc.) 
er minstens \'e\'en afgeschermd kan worden. De veiligheid en performantie van het prototype zullen beschreven worden in de evaluatie (hoofdstuk \ref{Evaluatie}).

\section{Policies toepassen}

Om een policy toe te passen op een stuk code is de \lstinline|Narcissus.interpreter.evaluate()| methode zo aangepast dat er een policy aan meegegeven kan worden als argument.
De meegegeven policy zal dan toegepast worden op de ge\"evalueerde code. Deze policy zal blijven toegepast worden op elk stuk code dat ge\"evalueerd wordt totdat er een nieuwe policy meegegeven wordt. 
Dit wil zeggen dat het policy argument optioneel is, en de laatst gebruikte policy van kracht blijft.

\medskip
\begin{lstlisting}[caption=Voorbeeld van een policy die meegegeven wordt met een stuk code.]
  Narcissus.interpreter.evaluate("alert(document.cookie);", {'cookie-read':'yes'});
\end{lstlisting}


\pagebreak

\section{Aanpassingen aan Narcissus}

Buiten de \lstinline|Narcissus.interpreter.evaluate()| functie zijn er nog twee andere functies aangepast en eentje toegevoegd.
De toegevoegde functie is de functie \lstinline|Narcissus.interpreter.parsePolicy()| die een policy object omzet naar een gegevensstructuur
die dan gebruikt wordt door de aangepaste \lstinline|Narcissus.intepreter.getValue()| en \lstinline|Narcissus.interpreter.putValue()| functies. 
Deze aanpassingen zullen binnen deze sectie beschreven worden.

\subsection{Narcissus.interpreter.evaluate()}

De originele \lstinline|Narcissus.interpreter.evaluate()| methode van Narcissus moest zo aangepast worden dat er een policy zou kunnen aan meegegeven worden. 
De meegegeven policy zal dan omgezet worden naar een interne gegevensstructuur door de \lstinline|Narcissus.interpreter.parsePolicy()| methode op te roepen.

\medskip
\begin{lstlisting}[caption=Originele Narcissus.interpreter.evaluate(). lib/jsexec.js]
 function evaluate(s, f, l) {
    if (typeof s !== "string")
        return s;
    var x = new ExecutionContext(GLOBAL_CODE, Narcissus.options.version);
    var ast = parser.parse(s, f, l);
    if (x.version === "harmony") {
       resolveGlobal(ast);
       nstantiateModules(ast, x.scope);
    }
    x.execute(ast);
    return x.result;
 }
\end{lstlisting}

\begin{lstlisting}[caption=Aangepaste Narcissus.interpreter.evaluate(). lib/jsexec.js]
 var activePolicy; //added
 var JSON_active_policy;//added
 function evaluate(s, p, f, l) {
    if (typeof s !== "string")
        return s;

    if(JSON_active_policy !== p || !activePolicy){ //added
       JSON_active_policy = p; //added
       activePolicy = parsePolicy(p); //added
    }
    var x = new ExecutionContext(GLOBAL_CODE, Narcissus.options.version);
    var ast = parser.parse(s, f, l);
    if (x.version === "harmony") {
       resolveGlobal(ast);
       nstantiateModules(ast, x.scope);
    }
    x.execute(ast);
    return x.result;
 }
\end{lstlisting}

\subsection{Narcissus.interpreter.parsePolicy()}

De methode \lstinline|Narcissus.interpreter.parsePolicy()| zet policies om naar een interne gegevensstructuur.
Deze gegevensstructuur bestaat uit twee hashtabelen, \'e\'en wordt gebruikt bij het lezen van operaties,
de andere bij het schrijven, deze tabellen noemen we \lstinline|read| en \lstinline|write|.
 
Elke tabel heeft als sleutels de gevoelige operaties die afgeschermd moeten worden. Bij read zijn de waarden van de tabel
dan gewoon de gevoelige operatie zelf indien toegestaan. Anders kan er ofwel een dummy functie of een dummy waarde teruggegeven worden.
Zo zal code die gebruik maakt van niet toegestane operaties, niet of toch in zo weinig mogelijk gevallen crashen.
Bij \lstinline|write| is de waarde \lstinline|'yes'| als het toegestaan is de functie of property te overschrijven, anderzijds is de waarde \lstinline|'no'|.

Listing \ref{lst:parsePolicy} toont een verkorte versie van de \lstinline|Narcissus.interpreter.parsePolicy()| methode. Het prototype zal
enkel een subset van alle gevoelige operaties kunnen afschermen. Deze subset hebben we zo gekozen dat er wel \'e\'en voorbeeld van alle soorten operaties afgeschermd wordt.

De soorten operaties zijn:
\begin{itemize}
  \setlength{\parskip}{0.0in}
  \setlength{\itemindent}{1.0em}
  \item Properties bv: document.cookie.
  \item Functies zonder callback bv: localStorage.setItem(), localStorage.getItem().
  \item Functies met callback bv: navigator.geolocation.watchPosition(), eventlisteners.
  \item Objecten bv: document.XMLHttpRequest, 
  \item DOM bv: document.getElementById(), document.createElement().
\end{itemize}

\pagebreak

\medskip
\begin{lstlisting}[caption=Verkorte versie van Narcissus.interpreter.parsePolicy(). lib/jsexec.js, label=lst:parsePolicy] 
 function parsePolicy(p) {
        p = (p == undefined) ? {} : p;
        var ruleSet = {}; 
        
        ruleSet.read = new Object();
        ruleSet.write = new Object();        
        if (p['cookie-read'] === 'yes') {
            Object.defineProperty( ruleSet.read[document], "cookie", { get : function() { return document.cookie; },
								       enumerable : true });
        } else {
            ruleSet.read[document]["cookie"] = 'No cookie reads allowed';
        }

        if (p['cookie-write'] == 'yes') {
            ruleSet.write[document]["cookie"] = 'yes';
        } else {
            ruleSet.write[document]["cookie"] = 'no';
        }
        
        if (p['domaccess-read'] === 'yes') {
            ruleSet.read[document]["getElementById"] = document.getElementById;
            ruleSet.write[document]["getElementById"] = 'no';
            //Add all other DOM read operations
        } else {
            ruleSet.read[document]["getElementById"] = function() { return "No DOM read access" };
            ruleSet.write[document]["getElementById"] = 'no';
            //Add all other DOM read operations
        }
        
        return ruleSet;
   }
\end{lstlisting}

Deze methode kan makkelijk uitgebreid worden om zo meer functies af te schermen. 
De functie moet gewoon toegevoegd worden aan de gegevensstructuur onder de juiste check. 
Listing \ref{lst:parsePolicy2} toont de nodige aanpassingen die moeten gemaakt worden om vertrekkende van Listing \ref{lst:parsePolicy} de methode \lstinline|document.getElementsByTagName()| ook te kunnen afschermen.

\pagebreak

\medskip
\begin{lstlisting}[caption=Verkorte versie van Narcissus.interpreter.parsePolicy(). lib/jsexec.js, label=lst:parsePolicy2] 
 function parsePolicy(p) {
        p = (p == undefined) ? {} : p;
        var ruleSet = {}; 
        
        ruleSet.read = new Object();
        ruleSet.write = new Object();        
        if (p['cookie-read'] === 'yes') {
            Object.defineProperty( ruleSet.read[document], "cookie", { get : function() { return document.cookie; },
								       enumerable : true });
        } else {
            ruleSet.read[document]["cookie"] = 'No cookie reads allowed';
        }

        if (p['cookie-write'] == 'yes') {
            ruleSet.write[document]["cookie"] = 'yes';
        } else {
            ruleSet.write[document]["cookie"] = 'no';
        }
        
        if (p['domaccess-read'] === 'yes') {
            ruleSet.read[document]["getElementById"] = document.getElementById;
            ruleSet.write[document]["getElementById"] = 'no';
            ruleSet.read[document]["getElementsByTagName"] = document.getElementsByTagName; //added
            ruleSet.write[document]["getElementsByTagName"] = 'no'; //added
            
            //Add all other DOM read operations
        } else {
            ruleSet.read[document]["getElementById"] = function() { return "No DOM read access" };
            ruleSet.write[document]["getElementById"] = 'no';
            ruleSet.read[document]["getElementsByTagName"] = function() { return "No DOM read access" }; //added
            ruleSet.write[document]["getElementsByTagName"] = 'no'; //added
            //Add all other DOM read operations
        }
        
        return ruleSet;
   }
\end{lstlisting}

\pagebreak

\subsection{Narcissus.interpreter.getValue()}
\label{getValueExp}
In JavaScript is alles een referentie naar een object, binnenin een JavaScript engine is er dus een functionaliteit die referenties kan
omzetten naar de objecten waarnaar ze wijzen. Deze functionaliteit wordt aangeboden in elke JavaScript engine onder de vorm van de methode \lstinline|getValue()|, deze methode wordt verder besproken in de JavaScript specificaties \cite{ecma}.

De referenties zijn in Narcissus ge\"implementeerd als \lstinline|Reference| objecten, dit zijn objecten met twee properties: \lstinline|Reference.base| en \lstinline|Reference.propertyName|.
\lstinline|Reference.base| houdt het basisobject bij en \lstinline|Reference.propertyName| houdt bij naar welke eigenschap van het basis object de \lstinline|Reference wijst. Een \lstinline|Reference| wijst dus altijd naar een property van een object. 
Dit is mogelijk omdat in JavaScript objecten altijd properties zijn van het object van de scope waarin ze zijn gecre\"eerd. In het geval van de global scope worden ze dan properties van het global object.
Een referentie naar het global object kan ook gemaakt worden want \'e\'en van de properties van het global object is het global object zelf.

\medskip
\begin{lstlisting}[caption=Originele Narcissus.interpreter.getValue(). lib/jsexec.js]
 function getValue(v) {
        if (v instanceof Reference) {
            if (!v.base) {
                var e = 'throw new ReferenceError("'+ v.propertyName + ' is not defined, ' + v.node.filename + ', ' + v.node.lineno + '");';
                Narcissus.interpreter.evaluate(e);
            }
            return v.base[v.propertyName];
        }
        return v;
    }
\end{lstlisting}

De methode \lstinline|Narcissus.intepreter.getValue()| is zo aangepast dat deze gebruikt maakt van de eerder aangemaakte gegevensstructuur 
in \lstinline|Narcissus.intepreter.parsePolicy()|. Als een gevraagde referentie aanwezig is in de \lstinline|read| tabel van de gegevensstructuur, zal de waarde van deze referentie in de \lstinline|read| tabel opgehaald worden en teruggegeven worden.
Deze methode slaagt er in om alle paden naar een bepaald object af te schermen omdat al deze paden referenties zijn naar hetzelfde object. 
Deze methode vergelijkt de objecten en niet de volledige referenties.

\pagebreak
 
\medskip
\begin{lstlisting}[caption=Aangepaste Narcissus.interpreter.getValue(). lib/jsexec.js]
 function getValue(v) {
    if (v instanceof Reference) {
        if (!v.base) {
            var e = 'throw new ReferenceError("'+ v.propertyName + ' is not defined, ' + v.node.filename + ', ' + v.node.lineno + '");';
            Narcissus.interpreter.evaluate(e);
        }
        if( activePolicy.read[v.base] && activePolicy.read[v.base][v.propertyName] !== undefined) {
            return activePolicy.read[v.base][v.propertyName];
        } else {
            return v.base[v.propertyName];
        }
    }
\end{lstlisting}

\subsection{Narcissus.interpreter.putValue()}

In JavaScript is niet enkel een functionaliteit nodig die objecten terug kan geven waarnaar referenties wijzen. 
Maar ook een methode die objecten waarnaar referenties wijzen, kan overschrijven. Deze functionaliteit wordt aangeboden in elke JavaScript engine onder
de vorm van de methode \lstinline|putValue()|. Deze methode wordt verder besproken in de JavaScript specificaties \cite{ecma}.

\medskip
\begin{lstlisting}[caption=Originele Narcissus.interpreter.putValue(). lib/jsexec.js]
 function putValue(v, w, vn) {
        if (v instanceof Reference) {
           return (v.base || global)[v.propertyName] = w;
        }
        var e = 'throw new ReferenceError("Invalid assignment left-hand side,'+ vn.filename + ', ' +vn.lineno + '”);';
        Narcissus.interpreter.evaie luate(e);
   }
\end{lstlisting}

De methode \lstinline|Narcissus.intepreter.putValue()| is zo aangepast dat deze gebruik maakt van de eerder aangemaakte gegevensstructuur in \lstinline|Narcissus.intepreter.parsePolicy()|. Als een gevraagde referentie aanwezig is in de write tabel van de gegevensstructuur zal het object waarnaar de referentie wijst enkel en alleen overschreven worden als de waarde in de \lstinline|write| tabel \lstinline|'yes'| is. Ook hier worden alle paden naar een object volledig afgeschermd.

\pagebreak

\medskip
\begin{lstlisting}[caption=Aangepaste Narcissus.interpreter.putValue(). lib/jsexec.js]
 function putValue(v, w, vn) {
     if (v instanceof Reference) {
         if(activePolicy.write[v.base] && activePolicy.write[v.base][v.propertyName] !== undefined) {
             return activePolicy.write[v.base][v.propertyName] === 'yes' ? v.base[v.propertyName] = w : null;
         } else {
             return (v.base || global)[v.propertyName] = w;
         }
     }
     var e = 'throw new ReferenceError("Invalid assignment left-hand side,'+ vn.filename + ', ' +vn.lineno + '”);';
     Narcissus.interpreter.evaluate(e);
 }
\end{lstlisting}

